package haha.life.normal;

import cnki.tpi.base.DataSourceManager;
import com.alibaba.fastjson.JSONObject;
import com.kbase.jdbc.ConnectionImpl;
import jzqb.common.Result;
import kbase.KBaseClient;
import org.icepdf.core.pobjects.Document;
import org.icepdf.core.pobjects.Page;
import org.icepdf.core.util.GraphicsRenderingHints;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;

public class FileuploadUtils {

    /**
     * 通过指定存储路径上传文件与图片
     *
     * @param file         文件
     * @param fileResource 文件基础路径
     * @return
     */
    public static String uploading(MultipartFile file, String fileResource) {
        String fileName = file.getOriginalFilename();
        String randDir = RandomUtils.getRandomString(8);
        String filePath = new File(fileResource, randDir).toString();
        try {
            //执行保存(文件,目录,文件名)
            FileUtil.saveFile(file, filePath, fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String[] split = fileResource.split("\\\\");
        String str3 = "";
        String jsonStr = "";
        String split1 = split[split.length - 2];
        String split2 = split[split.length - 1];
        str3 = split1 + "\\" + split2;
        String lastPath = new File(randDir, fileName).toString();
        jsonStr = FastJsonUtils.getBeanToJson(Result.succ(str3 + "\\" + lastPath));
//            jsonStr = FastJsonUtils.getBeanToJson(Result.succ(new File(randDir, fileName)));
        return jsonStr;
    }

    /**
     * 批量上传文件
     *
     * @param allFolderPath 文件存放的文件目录(不含文件名,文件名之前)
     * @param request       当前http请求
     * @return
     */
    public static Object fileBatchUploading(String allFolderPath, HttpServletRequest request) {
        Map<String, String> map = new HashMap<>();
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        if (fileMap == null || fileMap.size() == 0) {
            return Result.fail("请上传文件,注意文件的name属性为file");
        }
        Collection<MultipartFile> files = fileMap.values();
        for (MultipartFile file : files) {
            /**
             注意这里获取的个数，是根据前端form表单里有几个，type=file来决定的，
             比如你虽然只点选了一个文件，上传，但这里实际上回有两个MultipartFile对 象，只不过其中一个MutipartFile的文件名会为空，这就是为什么下边会有个判断文件名
             为空的步骤**/
            String fileName = file.getOriginalFilename();//上传文件的原名
            if (StringUtils.isEmpty(fileName)) {
                continue;
            }
            File tempFile = new File(allFolderPath, fileName);
            System.out.println("存放路径:" + tempFile.getAbsolutePath());
            if (!tempFile.exists()) {
                tempFile.getParentFile().mkdirs();
                try {
                    tempFile.createNewFile();
                    file.transferTo(tempFile); //到这里tempFile即是上传上来的文件 。
                    //文件存放绝对路径
                    String absolutePath = tempFile.getAbsolutePath();
                    String[] split = absolutePath.split("\\\\");
                    String laterPath = split[split.length - 3] + "\\" + split[split.length - 2] + "\\" + split[split.length - 1];
                    map.put(fileName, laterPath);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("文件名:" + fileName);
        }
        return map;
    }


    /**
     * 以流的方式下载文件
     *
     * @param absolutePath 文件存放绝对路径
     * @param response
     * @return
     */
    public static HttpServletResponse download(String absolutePath, HttpServletResponse response) {
        InputStream fis = null;
        OutputStream toClient = null;
        try {
            // path是指欲下载的文件的路径。
            File file = new File(absolutePath);
            try {
                // 以流的形式下载文件。
                fis = new BufferedInputStream(new FileInputStream(absolutePath));
            } catch (FileNotFoundException e) {//文件找不到,直接返回
              return response;
            }
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            // response.reset();  //不注释掉会有 org.apache.catalina.connector.ClientAbortException: java.io.IOException: 你的主机中的软件中止了一个已建立的连接
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "utf-8"));
            response.addHeader("Content-Length", "" + file.length());
            toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();

        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (toClient != null) {
                    toClient.close();
                }
                if (fis != null) {
                    toClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return response;
    }

    /**
     * 视频专用
     *
     * @param absolutePath 文件存放绝对路径
     * @param response
     * @return
     */
    public static HttpServletResponse downloadJSYY(String absolutePath, HttpServletResponse response) {
        InputStream fis = null;
        OutputStream toClient = null;
        try {
            // path是指欲下载的文件的路径。
            File file = new File(absolutePath);
            try {
                // 以流的形式下载文件。
                fis = new BufferedInputStream(new FileInputStream(absolutePath));
            } catch (FileNotFoundException e) {//文件找不到,直接返回
                return response;
            }
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            // response.reset();  //不注释掉会有 org.apache.catalina.connector.ClientAbortException: java.io.IOException: 你的主机中的软件中止了一个已建立的连接
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "utf-8"));
            response.addHeader("Content-Length", "" + file.length());
            toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();

        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (toClient != null) {
                    toClient.close();
                }
                if (fis != null) {
                    toClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return response;
    }


    /**
     * 下载本地文件
     *
     * @param absolutePath 文件存放绝对路径
     * @param response
     * @throws FileNotFoundException
     */
    public static void downloadLocal(String absolutePath, HttpServletResponse response) throws FileNotFoundException {
        String[] splitPath = absolutePath.split("\\\\");
        String fileName = splitPath[splitPath.length - 1];
        // 读到流中
        InputStream inStream = new FileInputStream(absolutePath);
        // 设置输出的格式
        //response.reset();  //不注释掉会有 org.apache.catalina.connector.ClientAbortException: java.io.IOException: 你的主机中的软件中止了一个已建立的连接
        response.setContentType("bin");
        response.addHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        // 循环取出流中的数据
        byte[] b = new byte[100];
        int len;
        try {
            while ((len = inStream.read(b)) > 0)
                response.getOutputStream().write(b, 0, len);

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 判断文件大小
     *
     * @param :multipartFile:上传的文件
     * @param size:                限制大小
     * @param unit:限制单位（B,K,M,G)
     * @return boolean:是否大于
     */
    public static boolean checkFileSize(MultipartFile multipartFile, int size, String unit) {
        long len = multipartFile.getSize();//上传文件的大小, 单位为字节.
        //准备接收换算后文件大小的容器
        double fileSize = 0;
        if ("B".equals(unit.toUpperCase())) {
            fileSize = (double) len;
        } else if ("K".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1024;
        } else if ("M".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1048576;
        } else if ("G".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1073741824;
        }
        //如果上传文件大于限定的容量
        if (fileSize > size) {
            return false;
        }
        return true;
    }


    /**
     * 将图像转化成二进制
     *
     * @param absolutePath 绝对路径
     * @return
     */
    public static byte[] getImageBinary(String absolutePath) {
        //图片转化为二进制
        byte[] imageBytes = null;
        File file = new File(absolutePath);
        try (FileInputStream fileInputStream = new FileInputStream(file);) {
            imageBytes = new byte[fileInputStream.available()];
            fileInputStream.read(imageBytes);
        } catch (IOException e) {
            //    e.printStackTrace();
        }
//        //二进制转化为图片
//        try (FileOutputStream fileOutputStream = new FileOutputStream(new File("C:/Users/2.jpg"));) {
//            fileOutputStream.write(imageBytes);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        return imageBytes;
    }

    /**
     * 移动文件夹下的全部文件 到另一个目录下
     *
     * @param from 从什么路径移动
     * @param to   移动到什么路径
     * @return
     * @throws Exception
     */
    public static Boolean fileMove(String from, String to) throws Exception {// 移动指定文件夹内的全部文件
        from = from.substring(0, from.lastIndexOf("\\"));
        to = to.substring(0, to.lastIndexOf("\\"));
        try {
            File dir = new File(from);
            File[] files = dir.listFiles();// 将文件或文件夹放入文件集
            if (files == null)// 判断文件集是否为空
                return true;
            File moveDir = new File(to);// 创建目标目录
            if (!moveDir.exists()) {// 判断目标目录是否存在
                moveDir.mkdirs();// 不存在则创建
            }
            for (int i = 0; i < files.length; i++) {// 遍历文件集
                if (files[i].isDirectory()) {// 如果是文件夹或目录,则递归调用fileMove方法，直到获得目录下的文件
                    fileMove(files[i].getPath(), to + "\\" + files[i].getName());// 递归移动文件
                    files[i].delete();// 删除文件所在原目录
                }
                File moveFile = new File(moveDir.getPath() + "\\"// 将文件目录放入移动后的目录
                        + files[i].getName());
                if (moveFile.exists()) {// 目标文件夹下存在的话，删除
                    moveFile.delete();
                }
                files[i].renameTo(moveFile);// 移动文件
                FileUtil.deleteFolder(from);//删除文件夹
                File oldFile = new File(from);// 创建旧文件
                File newFile = new File(to);// 创建新文件
                if (!oldFile.exists() && newFile.exists()) return true;
                return false;
            }
        } catch (Exception e) {
            throw e;
        }
        return false;
    }

    /**
     * 移动单个文件到指定文件夹
     *
     * @param from
     * @param to
     * @return
     */
    public static Boolean moveOneFile(String from, String to) {// 移动指定文件到指定文件夹
        String destDir = to.substring(0, to.lastIndexOf("\\"));
        File oldfile = new File(from);
        File newFile = new File(to);// 目标文件
        File newDir = new File(destDir);// 目标目录
        if (!newDir.exists()) newDir.mkdirs();// 不存在则创建目标目录
        oldfile.renameTo(newFile);// 移动文件
        if (newFile.exists()) return true;
        return false;
    }


    /**
     * 生成REC文件(分为新建和编辑)
     *
     * @param type:add,edit
     * @param obj:前端模型
     * @return REC字符串
     */
    public static String generRECfile(String jsonName,String type, String fileName, Integer sysID, Object obj) {
//        String jsonStr = FileUtil.readJsonFile("fieldsRemap_standard.json");
        String jsonStr = FileUtil.readJsonFile(jsonName);
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        //定义返回结果
        String RECfile = "";
        String nowStr = RandomUtils.nowStr("");
        if (type == "add") {
            RECfile = "<REC>";
            //记录添加时间
            RECfile = RECfile + "<SYS_FLD_RECORDADDDATE>=" + nowStr;
            //新建时,更新时间默认等于新建时间
            RECfile = RECfile + "<SYS_FLD_RECORDUPDATEDATE>=" + nowStr;
        } else if (type == "edit") {
            RECfile = "<REC>" + "<SYS_FLD_SYSID>=" + sysID;
            //记录数据更新时间
            RECfile = RECfile + "<SYS_FLD_RECORDUPDATEDATE>=" + nowStr;
        }
        //记录文件的更新时间
        if (fileName != "") {
            RECfile = RECfile + "<SYS_FLD_FILEUPDATEDATE>=" + nowStr;
        }
        //遍历前端对象,重映射key
        Field[] fields = obj.getClass().getDeclaredFields();
        for (int i = 0, len = fields.length; i < len; i++) {
            // 对于每个属性，获取属性名
            String varName = fields[i].getName();
            try {
                // 获取原来的访问控制权限
                boolean accessFlag = fields[i].isAccessible();
                // 修改访问控制权限
                fields[i].setAccessible(true);
                // 获取在对象f中属性fields[i]对应的对象中的变量
                Object o;
                try {
                    o = fields[i].get(obj);
                    try {
                        varName = jsonObject.get(varName).toString();
                        RECfile += String.format("<%s>=%s", varName, o);
                    } catch (NullPointerException e) {
                        continue;
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                // 恢复访问控制权限
                fields[i].setAccessible(accessFlag);
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
            }
        }
        return RECfile;
    }

    /**
     * 截取年限
     *
     * @param date
     * @return
     */
    public static String getYear(String date) {
        if (!"".equals(date) && date != null) {
            date = date.substring(0, 4);
        }
        return date;
    }

    public static void createFolw(String path, HttpServletResponse response) {
        // 取路径
        FileInputStream fis = null;
        OutputStream os = null;
        try {
            fis = new FileInputStream(path);
            os = response.getOutputStream();
            int count = 0;
            byte[] buffer = new byte[1024 * 8];
            while ((count = fis.read(buffer)) != -1) {
                os.write(buffer, 0, count);
                os.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            fis.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过Json生成REC文件
     *
     * @param obj
     * @return
     */
    public static String generRECfileByJSONObject(net.sf.json.JSONObject obj, String dbCode) {
        //excel中的字段
        String fields = null;
        if ("JZQBZS".equals(dbCode)) {
            fields = "题名,作者,文献来源,发表时间,年,领域,SYS_FLD_DIGITFILENAME,关键词,摘要,语言,全文,录入人";
        } else if("JZCG".equals(dbCode) || "JZZY".equals(dbCode)){
            fields = "题名,作者,文献来源,发表时间,年,领域,SYS_FLD_DIGITFILENAME,关键词,摘要,语言,全文,录入人,分类,期,封面";
        }else if("YQTZTWX".equals(dbCode)){
            fields = "专题集ID,专题ID,专题文献序号,题名,作者,文献来源,发表时间,年,领域,SYS_FLD_DIGITFILENAME,关键词,摘要,语言,全文,录入人";
        }
        ArrayList<String> allFileds = new ArrayList<String>();
        for (String s : fields.split(",")) {
            allFileds.add(s);
        }
        String RECfile = "<REC>";

        for (String s : allFileds) {
            String value = obj.get(s).toString();
            String temStr = String.format("<%s>=%s", s, value);
            RECfile += temStr;
        }
        String nowStr = RandomUtils.nowStr("");
        //写入记录添加时间
        String addStr = String.format("<SYS_FLD_RECORDADDDATE>=%s", nowStr);
        RECfile += addStr;
        //写入记录更新时间
        String updateStr = String.format("<SYS_FLD_RECORDUPDATEDATE>=%s", nowStr);
        RECfile += updateStr;
        //如果有文件
        String digitFileName = obj.getString("SYS_FLD_DIGITFILENAME");
        if (!("").equals(digitFileName)) {
            String digitFileNameStr = String.format("<SYS_FLD_FILEUPDATEDATE>=%s", nowStr);
            RECfile += digitFileNameStr;
        }
        return RECfile;
    }

    /**
     * 复制文件,并删除原文件
     *
     * @param s 文件的临时位置
     * @param t 文件的数据库目标位置
     * @return 执行结果
     */
    public static Boolean moveTempFileToDBFile(DataSourceManager con, String s, String t, String... arg) {
        ConnectionImpl conn = null;
        try {
            conn = (ConnectionImpl) con.getConnection();
            int hCon = conn.getConnectionHset();
            KBaseClient kBaseClient = conn.getKbaseClient();
            String tPath = t.substring(0, t.lastIndexOf("\\"));
            String sPath = s.substring(0, s.lastIndexOf("\\"));
            int tempRet = kBaseClient.KBase_MakeDir(hCon, tPath);
            int nRet = kBaseClient.KBase_WriteFile(hCon, s, t);
            if (nRet < 0) {
                return false;
            } else if (nRet == 0) {
                //写入文件到DB正常,删除临时文件
                if (arg.length == 0) {
                    FileUtil.deleteFolder(sPath);
                } else {
                    if (arg[0].equals("notDeleteDir")) {
                    }
                }
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (conn != null && !conn.isClosed())
                    conn.close();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    }


    /**
     * 删除原文件
     *
     * @param s 文件的数据库位置
     * @return 执行结果
     */
    public static Boolean deleteFileFromDBFile(DataSourceManager con, String s) {
        ConnectionImpl conn = null;
        try {
            conn = (ConnectionImpl) con.getConnection();
            int hCon = conn.getConnectionHset();
            KBaseClient kBaseClient = conn.getKbaseClient();
            int tempRet = kBaseClient.KBase_RemoveDir(hCon, s);
            if (tempRet <= 0) return false;
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (conn != null && !conn.isClosed())
                    conn.close();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    }

    /**
     * 将PDF首页自动转化成图片
     *
     * @param inputFile
     * @param outputFile
     */
    public static void pdfToPhoto(String inputFile, String outputFile) {
        Document document = null;
        String coverDir = outputFile.substring(0, outputFile.lastIndexOf("\\"));
        File newDir = new File(coverDir);// 目标目录
        if (!newDir.exists()) newDir.mkdirs();// 不存在则创建目标目录
        try {
            float rotation = 0f;//是否旋转
            float zoom = 0.5f;//缩略图显示倍数，1表示不缩放，0.5表示缩小到50%
            document = new Document();
            document.setFile(inputFile);
            BufferedImage image = (BufferedImage) document.getPageImage(0, GraphicsRenderingHints.SCREEN,
                    Page.BOUNDARY_CROPBOX, rotation, zoom);
            Iterator iter = ImageIO.getImageWritersBySuffix("png");
            ImageWriter writer = (ImageWriter) iter.next();
            FileOutputStream out = new FileOutputStream(new File(outputFile));
            ImageOutputStream outImage = ImageIO.createImageOutputStream(out);
            writer.setOutput(outImage);
            writer.write(new IIOImage(image, null, null));
            image.flush();
            image = null;
        } catch (Exception e) {
            e.printStackTrace();
        }
        document.dispose();
        document = null;
        System.gc();
    }


    /**
     * 复制文件,并删除原文件
     *
     * @param s 文件的临时位置
     * @param t 文件的数据库目标位置
     * @return 执行结果
     */
    public static Boolean moveTempOneFileToDBFile(DataSourceManager con, String s, String t, String... arg) {
        ConnectionImpl conn = null;
        try {
            conn = (ConnectionImpl) con.getConnection();
            int hCon = conn.getConnectionHset();
            KBaseClient kBaseClient = conn.getKbaseClient();
            String tPath = t.substring(0, t.lastIndexOf("\\"));
            String sPath = s.substring(0, s.lastIndexOf("\\"));
            int tempRet = kBaseClient.KBase_MakeDir(hCon, tPath);
            int nRet = kBaseClient.KBase_WriteFile(hCon, s, t);
            if (nRet < 0) {
                return false;
            } else if (nRet == 0) {
                //写入文件到DB正常,删除临时文件
                if (arg.length == 0) {
                    FileUtil.deleteFolder(s);
                } else {
                    if (arg[0].equals("notDeleteDir")) {
                    }
                }
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (conn != null && !conn.isClosed())
                    conn.close();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    }
}


